package com.hardy.job;

import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 不虚拟节点的一致性hash算法
 *
 * @author fuxiaohui3@nuoyuan.com.cn
 * @date 2018/10/22 11:23
 */
public class ConsistentHashingWithoutVirtualNode {
    private static String[] servers = {"192.168.0.0:111", "192.168.0.1:111", "192.168.0.2:111", "192.168.0.3:111", "192.168.0.4:111"};
    private static SortedMap<Integer, String> sortedMap = new TreeMap<Integer, String>();

    static {
        for (int i = 0; i < servers.length; i++) {
            int hash = getHash(servers[i]);
            System.out.println("["+servers[i]+"]"+"加入集合中，其hash值为"+hash);
            sortedMap.put(hash,servers[i]);
        }
    }

    /**
     * 使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法，最终效果没区别
     *
     * @param str
     * @return
     */
    private static int getHash(String str) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++) {
            hash = (hash ^ str.charAt(i)) * p;
        }
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        // 如果算出来的值为负数则取其绝对值
        if (hash < 0) {
            hash = Math.abs(hash);
        }
        return hash;
    }

    /**
     * 得到应当路由到的节点
     * @param node
     * @return
     */
    private static String getServer(String node){
        int hash = getHash(node);
        SortedMap<Integer,String> subMap = sortedMap.tailMap(hash);
        // 第一个key就是顺时针过去离node最近的那个节点
        if(subMap.isEmpty()){
            return sortedMap.get(sortedMap.firstKey());
        }
        Integer i = subMap.firstKey();
        return sortedMap.get(i);
    }

    public static void main(String[] args) {
        String[] keys = {"fuxiaohui","xuping","dongjianqiao"};
        for (int i=0;i<keys.length;i++){
            System.out.println("["+keys[i]+"]"+"的hash值"+getHash(keys[i])+","+"被路由到节点"+"["+getServer(keys[i])+"]");
        }
    }
}
